package com.yf.modules.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yf.Utils.CacheKey;
import com.yf.Utils.FileUtil;
import com.yf.Utils.RedisUtils;
import com.yf.dao.DepartmentMapper;
import com.yf.dao.RoleMapper;
import com.yf.dao.UserMapper;
import com.yf.domain.security.Department;
import com.yf.domain.security.User;
import com.yf.model.query.DeptQueryCriteria;
import com.yf.modules.system.service.api.DepartmentService;
import com.yf.response.exceptions.BusinessException;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author chentianwei
 * @date 2024-10-15 13:18
 * @description 部门操作业务实现层
 */
@Service
@Slf4j
public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Department> implements DepartmentService {

    private final DepartmentMapper departmentMapper;

    private final UserMapper userMapper;

    private final RoleMapper roleMapper;
    private final RedisUtils redisUtils;

    public DepartmentServiceImpl(DepartmentMapper departmentMapper,
                                 UserMapper userMapper,
                                 RoleMapper roleMapper,
                                 RedisUtils redisUtils) {

        this.departmentMapper = departmentMapper;
        this.userMapper = userMapper;
        this.roleMapper = roleMapper;
        this.redisUtils = redisUtils;
    }

    /**
     * 查询部门信息
     *
     * @param deptQueryCriteria 部门信息查询条件
     * @return 部门集合
     */
    @Override
    public List<Department> queryDepartment(DeptQueryCriteria deptQueryCriteria) {
        if (ObjectUtil.isEmpty(deptQueryCriteria.getPid())) {
            deptQueryCriteria.setPidIsNull(true);
        }
        return departmentMapper.findAll(deptQueryCriteria);
    }

    /**
     * 添加新的部门
     *
     * @param department 新部门
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addDept(Department department) {
        if (ObjectUtil.isNotEmpty(department.getId())) {
            throw new BusinessException("该" + department.getName() + "已存在，不可重复添加");
        }
        //保存实体
        save(department);
        //缓存清理
        updateSubCnt(department.getPid());
    }

    private void updateSubCnt(Long deptId) {
        if (deptId != null) {
            int count = departmentMapper.countByPid(deptId);
            departmentMapper.updateSubCntById(count, deptId);
        }
    }

    /**
     * 清理缓存
     *
     * @param id /
     */
    public void delCaches(Long id) {
        List<User> users = userMapper.findByRoleDeptId(id);
        // 删除数据权限
        redisUtils.delByKeys(CacheKey.DATA_USER, users.stream().map(User::getId).collect(Collectors.toSet()));
        redisUtils.del(CacheKey.DEPT_ID + id);
    }

    /**
     * 编辑部门信息
     *
     * @param department 编辑过的实体
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editDept(Department department) {
        // 旧的部门
        Long oldPid = getById(department.getId()).getPid();
        Long newPid = department.getPid();
        if (department.getPid() != null && department.getId().equals(department.getPid())) {
            throw new BusinessException("上级不能为自己");
        }
        Department dept = getById(department.getId());
        department.setId(dept.getId());
        saveOrUpdate(department);
        // 更新父节点中子节点数目
        updateSubCnt(oldPid);
        updateSubCnt(newPid);
        // 清理缓存
        delCaches(department.getId());
    }

    /**
     * 批量删除部门信息
     *
     * @param ids 主键
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteDept(Set<Long> ids) {
        Set<Department> departments = new HashSet<>();
        for (Long id : ids) {
            List<Department> deptList = departmentMapper.findByPid(id);
            departments.add(getById(id));
            if (CollectionUtil.isNotEmpty(deptList)) {
                departments = getDeleteDepts(deptList, departments);
            }
        }
        //验证是否有角色和用户关联，有关联情况下不允许删除
        verification(departments);

        for (Department department : departments) {
            //清理缓存
            delCaches(department.getId());
            departmentMapper.deleteById(department.getId());
            //更新节点数量
            updateSubCnt(department.getId());
        }
    }

    /**
     * 下载部门信息
     *
     * @param response Servlet返回流
     */
    @Override
    public void downloadDept(HttpServletResponse response) throws IOException {
        List<Department> departments = queryDepartment(new DeptQueryCriteria());
        List<Map<String, Object>> list = new ArrayList<>();
        for (Department dept : departments) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("部门名称", dept.getName());
            map.put("部门状态", dept.getEnabled() ? "启用" : "停用");
            map.put("创建日期", dept.getCreateTime());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    /**
     * 构建完整的部门树结构
     *
     * @param departmentList 部门数据
     * @return 树形结构表
     */
    @Override
    public Collection<Department> buildTree(List<Department> departmentList) {
        Set<Department> trees = new LinkedHashSet<>();
        Set<Department> depts = new LinkedHashSet<>();
        List<String> deptNames = departmentList.stream().map(Department::getName).toList();

        boolean isChild;

        for (Department dept : departmentList) {
            isChild = false;
            if (dept.getPid() == null) {
                trees.add(dept);
            }
            for (Department it : departmentList) {
                if (it.getPid() != null && dept.getId().equals(it.getPid())) {
                    isChild = true;
                    if (dept.getChildren() == null) {
                        dept.setChildren(new ArrayList<>());
                    }
                    dept.getChildren().add(it);
                }
            }
            if (isChild) {
                depts.add(dept);
            } else if (dept.getPid() != null && !deptNames.contains(getById(dept.getPid()).getName())) {
                depts.add(dept);
            }
        }

        if (CollectionUtil.isEmpty(trees)) {
            trees = depts;
        }
        return trees;
    }

    /**
     * 获取部门结构树
     *
     * @param ids 主键
     * @return 完整的部门树
     */
    @Override
    public Collection<?> getDeptSuperior(List<Long> ids) {
        Set<Department> departments = new LinkedHashSet<>();
        if (CollectionUtil.isNotEmpty(ids)) {
            for (Long id : ids) {
                Department department = getById(id);
                List<Department> superior = getSuperior(department, new ArrayList<>());
                for (Department data : superior) {
                    if (data.getId().equals(department.getPid())) {
                        data.setSubCount(data.getSubCount() - 1);
                    }
                }
                departments.addAll(superior);
            }
            //编辑部门时，不显示自己以级自己下级的数据，避免PID循环调用
            departments = departments.stream().filter(i -> !ids.contains(i.getId()) || ids.contains(i.getPid())).collect(Collectors.toSet());
            return buildTree(new ArrayList<>(departments));
        }
        return departmentMapper.findByPidIsNullOrderByMenuSort();
    }

    /**
     * 获取待删除的部门
     *
     * @param deptList    /
     * @param departments /
     * @return /
     */
    @Override
    public Set<Department> getDeleteDepts(List<Department> deptList, Set<Department> departments) {
        for (Department dept : deptList) {
            departments.add(dept);
            List<Department> depts = departmentMapper.findByPid(dept.getId());
            if (depts != null && depts.size() != 0) {
                getDeleteDepts(depts, departments);
            }
        }
        return departments;
    }

    /**
     * 验证是否被角色或用户关联
     *
     * @param departments /
     */
    @Override
    public void verification(Set<Department> departments) {
        Set<Long> deptIds = departments.stream().map(Department::getId).collect(Collectors.toSet());
        if (userMapper.countByDepts(deptIds) > 0) {
            throw new BusinessException("所选部门存在用户关联，请解除后再试！");
        }
        if (roleMapper.countByDepts(deptIds) > 0) {
            throw new BusinessException("所选部门存在角色关联，请解除后再试！");
        }
    }

    private List<Department> getSuperior(Department department, List<Department> departments) {
        if (department.getPid() == null) {
            departments.addAll(departmentMapper.findByPidIsNullOrderByMenuSort());
            return departments;
        }
        departments.addAll(departmentMapper.findByPidOrderByMenuSort(department.getPid()));
        return getSuperior(departmentMapper.selectById(department.getPid()), departments);
    }
}
